import { Injectable, Output, EventEmitter } from '@angular/core';
import { User } from 'src/app/user';
import { HttpClient, HttpResponse, HttpErrorResponse, HttpHeaders, HttpParams, HttpRequest } from '@angular/common/http';
import { Observable, of, config } from 'rxjs';
import { catchError, map, tap, retry } from 'rxjs/operators';
import { GlobalConfig } from 'src/app/share/global.config';

export class RequestOpts {
  url: string;
  data?: any = null;
  operation?: string;
  retryTimes?: number;
  headers?: HttpHeaders;
}
export class HttpRequestOpts extends RequestOpts {
  method?: string;
}

@Injectable()
export class UserCacheService {

  user: User;
  @Output() onchanged = new EventEmitter<User>();
  constructor(private cfg: GlobalConfig
    , private http: HttpClient) {
    console.log(`UserCacheService has constructor`);
   }
  setCacheUser(user: User) {
    const oldUser = this.user;
    this.user = user;
    if ((!oldUser && user)
    || ((oldUser && user)
    || oldUser.id !== user.id
    || oldUser.name !== user.name
    || oldUser.record !== user.record)) {
      this.onchanged.emit(this.user);
    }
  }
  get<T>(options: RequestOpts): Observable<T> {
      const params = new HttpParams({ fromObject: options.data });
      const retryTimes = options.retryTimes ? options.retryTimes : this.cfg.httpRetryTimes;
      const httpOptions = {params: params};
      return this.http.get<T>(options.url, httpOptions)
      .pipe(
        retry(retryTimes)
      );
  }
  post<T>(options: RequestOpts) {
      const retryTimes = options.retryTimes ? options.retryTimes : this.cfg.httpRetryTimes;
      const httpOptions = {headers: options.headers};
      return this.http.post<T>(options.url, options.data, httpOptions)
      .pipe(
        retry(retryTimes)
      );
  }
  request(options: HttpRequestOpts) {
    let params: HttpParams = null;
    let req: HttpRequest<any> = null;
    const retryTimes = options.retryTimes ? options.retryTimes : this.cfg.httpRetryTimes;
    let method: string;
    method = options.method || 'get';
    method = method.toLocaleLowerCase();
    let httpOptions: any = {headers: options.headers};
    if (method === 'get') {
      params = new HttpParams({ fromObject: options.data });
      httpOptions = {...httpOptions, params: params};
      req = new HttpRequest(method, options.url, httpOptions);
    } else {
      req = new HttpRequest(method, options.url, options.data, httpOptions);
    }
    return this.http.request(req)
    .pipe(
      retry(retryTimes)
    );
  }
  private handleError<T> (operation = 'operation', result?: T) {
    return (error: HttpErrorResponse): Observable<T> => {
      // TODO: better job of transforming error for user consumption
      this.log(`${operation} failed: ${error ? error.message : 'none'}`);
      // Let the app keep running by returning an empty result.
      return of(result as T);
    };
  }
  private log(message: any) {
    console.log(message);
  }
}
